package service

import (
	"bytes"
	"common/logs"
	"common/utils"
	"context"
	"core/dao"
	"core/models/db"
	"core/repo"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"framework/game"
	"hall/models/request"
	"io"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"
)

type NFTService struct {
	userDao *dao.UserDao
}

func (s *NFTService) CreateAccount(ctx context.Context, uid uint) {
	uidStr := fmt.Sprintf("%d", uid)
	request := &request.AccountCreateReq{
		Name:        fmt.Sprintf("ship_%d", uid),
		OperationId: utils.MathInviteCode(64-len(uidStr)) + uidStr,
	}
	result, err := s.accountCreate(request)
	if err.Err != nil || result.StatusCode != 200 {
		byteResultStr, _ := json.Marshal(result)
		logs.Info("UID:%d,result=%v,err:%v", uid, string(byteResultStr), err.Error)
		return
	}
	errs := s.userDao.UpdateUserMap(ctx, uid, &db.User{
		EthAddress:  &result.Data.Account,
		OperationID: &request.OperationId,
	})
	if errs == nil {
		byteResultStr, _ := json.Marshal(result)
		logs.Info("UID:%d,err:%s", uid, string(byteResultStr))
	}
}

func (s *NFTService) accountCreate(req *request.AccountCreateReq) (res request.AccountCreateDTO, errDTO request.ErrorDTO) {
	p, err := json.Marshal(&req)
	if err != nil {
		errDTO.Err = err
		return
	}
	conf := game.Conf.GameConfig["nft"]["value"].(map[string]any)
	url := fmt.Sprintf("%v%v", conf["domain"], conf["create_account"])
	resp, err := s.postHeader(url, p)
	if err != nil {
		errDTO.Err = err
		logs.Error("%v", err.Error())
		return
	}
	body, err := ioutil.ReadAll(resp.Body)
	defer func(Body io.ReadCloser) {
		err = Body.Close()
		if err != nil {
			logs.Error("%v", err.Error())
		}
	}(resp.Body)
	if err != nil {
		errDTO.Err = err
		logs.Error("%v", err.Error())
		return
	}
	if resp.StatusCode == 400 {
		err = json.Unmarshal(body, &errDTO)
	} else if resp.StatusCode == 200 {
		err = json.Unmarshal(body, &res)
	}
	// 设置状态和状态码
	errDTO.Status = resp.Status
	errDTO.StatusCode = resp.StatusCode
	//errDTO.Error.Message = resp.
	res.Status = resp.Status
	res.StatusCode = resp.StatusCode
	if err != nil {
		logs.Error("%v", err.Error())
		return
	}
	return res, errDTO
}

func (s *NFTService) postHeader(url string, param []byte) (*http.Response, error) {
	client := &http.Client{}
	req, err := http.NewRequest("POST", url, bytes.NewReader(param))
	if err != nil {
		return nil, err
	}
	//验签
	conf := game.Conf.GameConfig["nft"]["value"].(map[string]any)
	reqS := s.signRequest(req, conf["api_key"].(string), conf["api_secret"].(string))
	reqS.Header.Set("Content-Type", "application/json")
	resp, err := client.Do(reqS)
	return resp, err
}

func (s *NFTService) signRequest(req *http.Request, apiKey, apiSecret string) *http.Request {
	timestamp := strconv.FormatInt(time.Now().UnixNano()/int64(time.Millisecond), 10)
	// 获取 path params
	params := make(map[string]any)
	params["path_url"] = req.URL.Path
	// 获取 query params
	for k, v := range req.URL.Query() {
		k = "query_" + k
		params[k] = v[0]
	}
	// 获取 body params
	// 把request的内容读取出来
	var bodyBytes []byte
	if req.Body != nil {
		bodyBytes, _ = ioutil.ReadAll(req.Body)
	}
	// 把刚刚读出来的再写进去
	if bodyBytes != nil {
		req.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
	}
	paramsBody := make(map[string]any)
	_ = json.Unmarshal(bodyBytes, &paramsBody)
	hexHash := s.hash(timestamp + apiSecret)
	for k, v := range paramsBody {
		k = "body_" + k
		params[k] = v
	}
	sortParams := params
	if sortParams != nil {
		sortParamsBytes, _ := json.Marshal(sortParams)
		hexHash = s.hash(string(sortParamsBytes) + timestamp + apiSecret)
	}
	req.Header.Set("X-Api-Key", apiKey)
	req.Header.Set("X-Signature", hexHash)
	req.Header.Set("X-Timestamp", timestamp)
	return req
}

func (s *NFTService) hash(oriText string) string {
	oriTextHashBytes := sha256.Sum256([]byte(oriText))
	return hex.EncodeToString(oriTextHashBytes[:])
}

func NewNFTService(r *repo.Manager) *NFTService {
	return &NFTService{
		userDao: dao.NewUserDao(r),
	}
}
